
using FlatRedBall;
using FlatRedBall.Graphics;
using FlatRedBall.Math.Geometry;

using Microsoft.Xna.Framework.Audio;

using Xzipit.Utilities;
using FlatRedBall.Graphics.Animation;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using System;
using Xzipit.Interfaces;
using Xzipit.Utilities.Gestures;

namespace Xzipit.MenuObjects
{
    class WorldButtonList : MenuObject
    {
        #region Fields

        private List<WorldButton> _buttons;
        private WorldButton _focusedWorld;
        private float _preDragX;
        private float _nextX;

        private int _numWorlds;
        private GameGesture _drag;

        private const float OFFSET = 16.0f;
        private const float SHIFT_VELOCITY = 35.0f;
        private const float SHIFT_VELOCITY_2 = 100.0f;
        private const float DRAG_THRESHOLD = 2.0f;

        private enum ButtonState
        {
            Idle,
            MoveLeft,
            MoveRight,
            Selected
        }

        private ButtonState _state;

        #endregion

        #region Properties
        // All properties of Button are already covered in Obstacle.
        public WorldButton FocusedWorld
        {
            get { return _focusedWorld; }
        }

        public bool TransitionReady
        {
            get;
            private set;
        }
        #endregion

        #region Methods

        // Constructor
        public WorldButtonList(string contentManagerName, int numWorlds)
        {
            // Set the ContentManagerName and call Initialize:
            _numWorlds = numWorlds;

            // If you don't want to add to managers, make an overriding constructor
            Initialize(true);
        }

        protected override void Initialize(bool addToManagers)
        {
            // Here you can preload any content you will be using
            // like .scnx files or texture files.

            if (addToManagers)
            {
                AddToManagers(null);
            }
        }

        public override void AddToManagers(Layer layerToAddTo)
        {
            SpriteManager.AddPositionedObject(this);
            _buttons = new List<WorldButton>(_numWorlds);
            InitializeButtons();

            _touchSound = FlatRedBallServices.Load<SoundEffect>(@"Content\Sound\button");

            _state = ButtonState.Idle;
            TransitionReady = false;
        }

        public override void Activity()
        {
            if (_state == ButtonState.Selected)
            {
                if (!_focusedWorld.Enlarge())
                {
                    TransitionReady = true;
                }
            }
            else
            {
                foreach (GameGesture g in GameGestureManager.Gestures)
                {
                    if (WasTapped(g))
                    {
                        OnTap();
                        break;
                    }
                    else if (WasPulled(g))
                    {
                        OnPull();
                        break;
                    }
                    else if (WasDragged(g))
                    {
                        OnDrag(g);
                        break;
                    }
                    else
                    {
                        _state = ButtonState.Idle;
                    }
                }
            }

            if (_state == ButtonState.Idle)
            {
                _preDragX = this.X;
            }
        }

        public virtual void Destroy()
        {
            base.Destroy();

            foreach (WorldButton b in _buttons)
            {
                b.Destroy();
            }
        }

        public void MoveToButton(int worldNum)
        {
            _focusedWorld = _buttons[worldNum - 1];

            float finalX = OFFSET * (worldNum - 1);

            this.Velocity = Vector3.Zero;
            this.Acceleration = Vector3.Zero;
            this.X = -OFFSET * (worldNum - 1);

            if (_state != ButtonState.Selected)
            {
                _state = ButtonState.Idle;
            }

        }

        #region Private Methods
        private void InitializeButtons()
        {
            float startingX = 0.0f;

            for (int i = 0; i < _numWorlds; i++)
            {
                WorldButton b = new WorldButton("Global", i + 1);

                b.AttachTo(this, false);
                b.RelativeX = startingX + (i * OFFSET);

                _buttons.Add(b);

            }

            _focusedWorld = _buttons[0];
        }

        private void MoveToButton()
        {
            int worldNum = GetWorldNumber();

            _nextX = -OFFSET * worldNum;

            int dir = _nextX < this.X ? -1 : 1; 

            this.XVelocity = dir * SHIFT_VELOCITY;
            
            _state = dir < 0 ? ButtonState.MoveLeft : ButtonState.MoveRight;
        }

        private void SnapToButton()
        {
            int worldNum = GetWorldNumber();

            this.Velocity = Vector3.Zero;
            this.Acceleration = Vector3.Zero;
            this.X = -OFFSET * worldNum;

            if (_state != ButtonState.Selected)
            {
                _state = ButtonState.Idle;
            }
        }

        private int GetWorldNumber()
        {
            // set the world num default to the current focused world.
            int worldNum = _focusedWorld.World - 1;
            if (_state == ButtonState.MoveRight)
            {
                //worldNum = (int)Math.Round((double)(this.X / OFFSET));
                worldNum--;
            }
            else if (_state == ButtonState.MoveLeft)
            {
                worldNum++;
            }

            // min/max the world num
            if (worldNum < 0)
            {
                worldNum = 0;
            }
            else if (worldNum > GameProperties.TOTAL_WORLDS - 1)
            {
                worldNum = GameProperties.TOTAL_WORLDS - 1;
            }

            _focusedWorld = _buttons[worldNum];

            return worldNum;
        }

        private void StopMovement()
        {
            this.Velocity = Vector3.Zero;
            this.Acceleration = Vector3.Zero;
            _state = ButtonState.Idle;
        }

        #region Gesture Management

        #region Tap
        private bool WasTapped(GameGesture g)
        {

            foreach (WorldButton b in _buttons)
            {
                Vector3 gestureEnd = g.End;
                if (g.GameGestureType == GameGestureType.Tap
                    && b.Collision.IsPointInside(ref gestureEnd))
                {
                    _focusedWorld = b;
                    return true;
                }
            }

            return false;
        }

        private void OnTap()
        {
            GameProperties.Vibrate(.05);
            GameProperties.SelectedWorld = _focusedWorld.World;
            _focusedWorld.PlaySound();
            _focusedWorld.Enlarge();
            _state = ButtonState.Selected;

            SnapToButton();

        }
        #endregion

        #region Pull

        private bool WasPulled(GameGesture g)
        {
            return (g.Id == _drag.Id && g.GameGestureType == GameGestureType.Pull);
        }

        private void OnPull()
        {
            SnapToButton();
            _drag = new GameGesture(GameGestureType.Drag, Vector3.Zero, Vector3.Zero, -1, -1);
        }

        #endregion

        #region Drag
        private bool WasDragged(GameGesture g)
        {
            return ((_drag.StartTime <= 0 || _drag.Id == g.Id)
                    && g.GameGestureType == GameGestureType.Drag);
        }

        private void OnDrag(GameGesture g)
        {
            float dx = g.End.X - g.Start.X;

            this.XVelocity = 0.0f;
            this.XAcceleration = 0.0f;
            this.X = _preDragX + dx;
            _state = dx < 0 ? ButtonState.MoveLeft : ButtonState.MoveRight;
            _drag = g;
        }

        #endregion

        #endregion
        #endregion

        #endregion
    }
}
